/**   
* @Title: RedissonTestCase.java
* @Package me.cloud
* @Description: TODO
* @author xaoyaoyao
* @date Jan 10, 2019 1:23:52 PM
* @version V1.0   
*/
package me.cloud;

import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.redisson.RedissonMultiLock;
import org.redisson.RedissonRedLock;
import org.redisson.api.RCountDownLatch;
import org.redisson.api.RLock;
import org.redisson.api.RPermitExpirableSemaphore;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import redis.clients.jedis.JedisPool;

/**
 * @ClassName: RedissonTestCase
 * @Description: TODO
 * @author xaoyaoyao
 * @date Jan 10, 2019 1:23:52 PM
 * 
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = { LockApplication.class }) // 指定启动类
public class RedissonTestCase {

	private static final String LOCK_TITLE = "redisLock_";

	@Autowired
	private RedissonClient redisson;

	@Autowired
	private RedissonClient redisson2;

	@Autowired
	private RedissonClient redisson3;

	@Autowired
	private JedisPool jedisPool;

	public void acquire(String lockName) {
		String key = LOCK_TITLE + lockName;
		RLock mylock = redisson.getLock(key);
		mylock.lock(60, TimeUnit.MINUTES); // lock提供带timeout参数，timeout结束强制解锁，防止死锁
		System.err.println("======lock======" + Thread.currentThread().getName());
	}

	public void release(String lockName) {
		String key = LOCK_TITLE + lockName;
		RLock mylock = redisson.getLock(key);
		mylock.unlock();
		System.err.println("======unlock======" + Thread.currentThread().getName());
	}

	@Test
	public void testRedisLock() {
		for (int i = 0; i < 100; i++) {
			Thread t = new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						String key = "test123";
						acquire(key);
						Thread.sleep(1000); // 获得锁之后可以进行相应的处理
						System.err.println("======获得锁后进行相应的操作======");
						release(key);
						System.err.println("=============================");
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			});
			t.start();
		}
	}

	@Test
	public void testReentrantLock() {
		RLock lock = redisson.getLock("anyLock");
		try {
			// 1. 最常见的使用方法
			// lock.lock();
			// 2. 支持过期解锁功能,10秒钟以后自动解锁, 无需调用unlock方法手动解锁
			// lock.lock(10, TimeUnit.SECONDS);
			// 3. 尝试加锁，最多等待3秒，上锁以后10秒自动解锁
			System.out.println(">>>>> tryLock >> " + System.currentTimeMillis());
			boolean res = lock.tryLock(15, 30, TimeUnit.SECONDS);
			System.out.println(">>>>> tryLock >> " + res + " >> " + System.currentTimeMillis());
			if (res) { // 成功
				// do your business
				System.out.println("======OK=====" + System.currentTimeMillis());
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	@Test
	public void testAsyncReentrantLock() {
		RLock lock = redisson.getLock("anyLock");
		try {
			System.out.println(">>>>> tryLock >> " + System.currentTimeMillis());
			lock.lockAsync();
			lock.lockAsync(10, TimeUnit.SECONDS);
			Future<Boolean> res = lock.tryLockAsync(10, 20, TimeUnit.SECONDS);
			System.out.println(">>>>> Result >> " + System.currentTimeMillis());
			if (res.get()) {
				System.out.println("======OK=====" + System.currentTimeMillis());
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	@Test
	public void testFairLock() {
		RLock fairLock = redisson.getFairLock("anyLock");
		try {
			System.out.println(">>>>> tryLock >> " + System.currentTimeMillis());
			// 最常见的使用方法
			fairLock.lock();
			// 支持过期解锁功能, 10秒钟以后自动解锁,无需调用unlock方法手动解锁
			fairLock.lock(50, TimeUnit.SECONDS);
			// 尝试加锁，最多等待100秒，上锁以后10秒自动解锁
			boolean res = fairLock.tryLock(100, 10, TimeUnit.SECONDS);
			System.out.println(">>>>> tryLock >> " + res + " >> " + System.currentTimeMillis());
			if (res) { // 成功
				// do your business
				System.out.println("======OK=====" + System.currentTimeMillis());
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			fairLock.unlock();
		}
	}

	@Test
	public void testAsyncFairLock() {
		RLock fairLock = redisson.getFairLock("anyLock");
		try {
			System.out.println(">>>>> tryLock >> " + System.currentTimeMillis());
			fairLock.lockAsync();
			fairLock.lockAsync(10, TimeUnit.SECONDS);
			Future<Boolean> res = fairLock.tryLockAsync(100, 10, TimeUnit.SECONDS);
			System.out.println(">>>>> tryLock >> " + res + " >> " + System.currentTimeMillis());
			if (res.get()) { // 成功
				// do your business
				System.out.println("======OK=====" + System.currentTimeMillis());
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		} finally {
			fairLock.unlock();
		}
	}

	@Test
	public void testMultiLock() {
		RLock lock1 = redisson.getLock("lock1");
		RLock lock2 = redisson2.getLock("lock2");
		RLock lock3 = redisson3.getLock("lock3");
		RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3);
		try {
			System.out.println(">>>>> tryLock >> " + System.currentTimeMillis());
			// 同时加锁：lock1 lock2 lock3, 所有的锁都上锁成功才算成功。
			lock.lock();
			// 尝试加锁，最多等待100秒，上锁以后10秒自动解锁
			boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
			System.out.println(">>>>> tryLock >> " + res + " >> " + System.currentTimeMillis());
			if (res) { // 成功
				// do your business
				System.out.println("======OK=====" + System.currentTimeMillis());
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	@Test
	public void testRedLock() {
		RLock lock1 = redisson.getLock("lock1");
		RLock lock2 = redisson2.getLock("lock2");
		RLock lock3 = redisson3.getLock("lock3");
		RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3);
		try {
			System.out.println(">>>>> tryLock >> " + System.currentTimeMillis());
			// 同时加锁：lock1 lock2 lock3, 红锁在大部分节点上加锁成功就算成功。
			lock.lock();
			// 尝试加锁，最多等待100秒，上锁以后10秒自动解锁
			boolean res = lock.tryLock(30, 10, TimeUnit.SECONDS);
			System.out.println(">>>>> tryLock >> " + res + " >> " + System.currentTimeMillis());
			if (res) { // 成功
				// do your business
				System.out.println("======OK=====" + System.currentTimeMillis());
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	@Test
	public void testRReadWriteLock() {
		RReadWriteLock rwlock = redisson.getReadWriteLock("anyLock");
		try {
			System.out.println(">>>>> readLock >> " + System.currentTimeMillis());
			rwlock.readLock().lock(10, TimeUnit.SECONDS);
			boolean res = rwlock.readLock().tryLock(100, 10, TimeUnit.SECONDS);
			System.out.println(">>>>> readLock >> " + res + " >> " + System.currentTimeMillis());
			if (res) { // 成功
				// do your business
				System.out.println("======OK=====" + System.currentTimeMillis());
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			rwlock.readLock().unlock();
		}
	}

	@Test
	public void testRReadWriteLock2() {
		RReadWriteLock rwlock = redisson.getReadWriteLock("anyLock");
		try {
			System.out.println(">>>>> writeLock >> " + System.currentTimeMillis());
			rwlock.writeLock().lock(10, TimeUnit.SECONDS);
			boolean res = rwlock.writeLock().tryLock(100, 10, TimeUnit.SECONDS);
			System.out.println(">>>>> writeLock >> " + res + " >> " + System.currentTimeMillis());
			if (res) { // 成功
				// do your business
				System.out.println("======OK=====" + System.currentTimeMillis());
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			rwlock.writeLock().unlock();
		}
	}

	@Test
	public void testRSemaphore() {
		RSemaphore semaphore = redisson.getSemaphore("semaphore");
		try {
			semaphore.acquireAsync();
			// semaphore.acquire(23);
			// semaphore.acquire();
			semaphore.tryAcquireAsync();
			// semaphore.tryAcquire(23, TimeUnit.SECONDS);
			// semaphore.tryAcquire();
			// semaphore.tryAcquireAsync(23, TimeUnit.SECONDS);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			semaphore.releaseAsync();
			// semaphore.release(10);
			// semaphore.release();
		}
	}

	@Test
	public void testRPermitExpirableSemaphore() {
		RPermitExpirableSemaphore semaphore = redisson.getPermitExpirableSemaphore("mySemaphore");
		String permitId = null;
		try {
			// permitId = semaphore.acquire();
			// 获取一个信号，有效期只有5秒钟。
			permitId = semaphore.acquire(5, TimeUnit.SECONDS);
			System.out.println(">>>>>>>> permitId >> " + permitId);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			semaphore.release(permitId);
		}
	}

	@Test
	public void testRCountDownLatch() {
		RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
		latch.trySetCount(1);
		try {
			latch.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			latch.countDown();
		}
	}

	@Test
	public void testLock() {
		System.out.println("---------->>> " + Thread.currentThread().getName());
		Integer id = 10000000;
		String randomValue = id + UUID.randomUUID().toString();// 随机值，确保全局唯一
		System.out.println(">>>>>>>> lock >>> " + System.currentTimeMillis());
		RedisDistributedLock.acquireLock(jedisPool.getResource(), id.toString(), randomValue, 5 * 1000);// 加锁
		// 业务逻辑
		System.out.println(">>>>>>>> lock >>> " + System.currentTimeMillis());
		RedisDistributedLock.releaseLock(jedisPool.getResource(), id.toString(), randomValue);// 释放锁
	}
}
